"""
数据模型定义模块

定义了爬虫项目中使用的所有数据结构和模型。
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, List
import re


@dataclass
class ScrapedData:
    """
    爬取的数据模型

    包含从网页中提取的关键信息字段。
    """
    title: str                    # 标题
    registration_time: str        # 登记时间
    reply_unit: str              # 答复单位
    reply_time: str              # 答复时间
    source_url: str              # 来源网址
    scraped_at: datetime = field(default_factory=datetime.now)  # 爬取时间
    content: Optional[str] = None  # 内容（可选）

    def __post_init__(self):
        """数据后处理，清理和标准化字段"""
        self.title = self._clean_text(self.title)
        self.registration_time = self._standardize_time(self.registration_time)
        self.reply_unit = self._clean_text(self.reply_unit)
        self.reply_time = self._standardize_time(self.reply_time)
        if self.content:
            self.content = self._clean_text(self.content)

    def _clean_text(self, text: str) -> str:
        """
        清理文本内容

        Args:
            text: 原始文本

        Returns:
            清理后的文本
        """
        if not text:
            return ""

        # 移除多余的空白字符
        text = re.sub(r'\s+', ' ', text.strip())
        # 移除特殊字符
        text = re.sub(r'[^\w\s\u4e00-\u9fff\-\.\(\)（）]', '', text)
        return text

    def _standardize_time(self, time_str: str) -> str:
        """
        标准化时间格式

        Args:
            time_str: 原始时间字符串

        Returns:
            标准化后的时间字符串
        """
        if not time_str:
            return ""

        # 常见的中文时间格式处理
        time_patterns = [
            r'(\d{4})年(\d{1,2})月(\d{1,2})日',
            r'(\d{4})-(\d{1,2})-(\d{1,2})',
            r'(\d{4})/(\d{1,2})/(\d{1,2})',
        ]

        for pattern in time_patterns:
            match = re.search(pattern, time_str)
            if match:
                year, month, day = match.groups()
                return f"{year}-{month.zfill(2)}-{day.zfill(2)}"

        return time_str.strip()

    def to_dict(self) -> dict:
        """转换为字典格式"""
        return {
            'title': self.title,
            'registration_time': self.registration_time,
            'reply_unit': self.reply_unit,
            'reply_time': self.reply_time,
            'source_url': self.source_url,
            'scraped_at': self.scraped_at.isoformat(),
            'content': self.content
        }

    def __str__(self) -> str:
        """字符串表示"""
        return f"ScrapedData(title='{self.title}', source='{self.source_url}')"


@dataclass
class ScrapingResult:
    """
    爬取结果模型

    包含单次爬取的结果和元数据。
    """
    url: str                      # 爬取的URL
    success: bool                 # 是否成功
    data: List[ScrapedData] = field(default_factory=list)  # 爬取的数据
    error_message: Optional[str] = None  # 错误信息
    scraped_at: datetime = field(default_factory=datetime.now)  # 爬取时间
    processing_time: float = 0.0  # 处理时间（秒）

    def add_data(self, data: ScrapedData) -> None:
        """添加爬取数据"""
        self.data.append(data)

    def get_data_count(self) -> int:
        """获取数据条数"""
        return len(self.data)

    def is_empty(self) -> bool:
        """检查是否为空"""
        return len(self.data) == 0


@dataclass
class WebsiteConfig:
    """
    网站配置模型

    定义单个网站的爬取配置。
    """
    name: str                     # 网站名称
    url: str                      # 网站URL
    scraper_type: str             # 爬虫类型
    selectors: dict               # CSS选择器配置
    enabled: bool = True          # 是否启用
    max_retries: int = 3          # 最大重试次数
    timeout: int = 30             # 超时时间（秒）
    delay: float = 1.0            # 请求间隔（秒）

    def __post_init__(self):
        """验证配置"""
        if not self.name or not self.url:
            raise ValueError("网站名称和URL不能为空")

        if self.max_retries < 0:
            raise ValueError("最大重试次数不能为负数")

        if self.timeout <= 0:
            raise ValueError("超时时间必须大于0")

        if self.delay < 0:
            raise ValueError("请求间隔不能为负数")
